package com.yjzx.util.common.util.map;

import java.util.*;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

/**
 * @author yjzx
 * @date 2023/3/24 10:42
 * @Description
 */
public class ListNode<K, V> implements List<NodeMap<K, V>> {
    private final List<NodeMap<K, V>> list;

    public ListNode() {
        this(new ArrayList<>());
    }

    public ListNode(K key, V value) {
        this(new ArrayList<>());
        add(new NodeMap<>(key, value));
    }

    public ListNode(ListNode<K, V> list) {
        this(list.list);
    }

    public ListNode(List<NodeMap<K, V>> list) {
        this.list = list == null ? new ArrayList<>() : new ArrayList<>(list);
    }

    public ListNode(Map<K, V> map) {
        this(map.entrySet().stream().map(NodeMap::of).collect(Collectors.toList()));
    }

    public List<NodeMap<K, V>> toList() {
        return new ArrayList<>(list);
    }

    public boolean containsKey(Object o) {
        return o == null ? list.stream().anyMatch(x -> x == null || x.getKey() == null) : list.stream().anyMatch(x -> o.equals(x == null ? null : x.getKey()));
    }

    public boolean containsValue(Object o) {
        return o == null ? list.stream().anyMatch(x -> x == null || x.getValue() == null) : list.stream().anyMatch(x -> o.equals(x == null ? null : x.getValue()));
    }

    public Map<K, V> toMap() {
        return list.size() > 0 ? toMap(NodeMap::getKey, NodeMap::getValue) : new HashMap<>();
    }

    public <U, W> Map<U, W> toMap(Function<NodeMap<K, V>, U> keyMapper, Function<NodeMap<K, V>, W> valueMapper) {
        int size = hashMapSize();
        Map<U, W> map = new HashMap<>(size);
        for (NodeMap<K, V> nodeMap : this.list) {
            map.put(keyMapper.apply(nodeMap), valueMapper.apply(nodeMap));
        }
        return map;
    }

    public <R> Set<R> toSet(Function<NodeMap<K, V>, R> valueMapper) {
        int size = hashMapSize();
        Set<R> set = new HashSet<>(size);
        for (NodeMap<K, V> nodeMap : this.list) {
            set.add(valueMapper.apply(nodeMap));
        }
        return set;
    }

    private int hashMapSize() {
        int size = (int) (this.list.size() / 0.75);
        int a = 1;
        while (size > 1) {
            size = size >> 1;
            a++;
        }
        size = 1 << Math.min(a, 8);
        return size;
    }

    public ListNode<K, V> add(K key, V value) {
        add(new NodeMap<>(key, value));
        return this;
    }

    public ListNode<K, V> addAll(ListNode<K, V> list) {
        if (list != null) {
            this.list.addAll(list.list);
        }
        return this;
    }

    public <T> ListNode<K, V> addAll(Collection<T> collection, Function<T, NodeMap<K, V>> function) {
        if (collection != null && collection.size() > 0 && function != null) {
            this.list.addAll(collection.stream().map(function).collect(Collectors.toList()));
        }
        return this;
    }

    public <U, W> ListNode<K, V> addAll(Map<U, W> map, Function<Map.Entry<U, W>, NodeMap<K, V>> function) {
        if (map != null && map.size() > 0 && function != null) {
            this.list.addAll(map.entrySet().stream().map(function).collect(Collectors.toList()));
        }
        return this;
    }

    @Override
    public boolean add(NodeMap<K, V> model) {
        return list.add(model);
    }

    @Override
    public boolean addAll(Collection<? extends NodeMap<K, V>> collection) {
        return this.list.addAll(collection);
    }

    @Override
    public int size() {
        return list.size();
    }

    @Override
    public boolean isEmpty() {
        return list.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return list.contains(o);
    }

    @Override
    public Iterator<NodeMap<K, V>> iterator() {
        return list.iterator();
    }

    @Override
    public Object[] toArray() {
        return list.toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return list.toArray(a);
    }

    @Override
    public boolean remove(Object o) {
        return list.remove(o);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return list.containsAll(c);
    }

    @Override
    public boolean addAll(int index, Collection<? extends NodeMap<K, V>> c) {
        return list.addAll(index, c);
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return list.removeAll(c);
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return list.retainAll(c);
    }

    @Override
    public void replaceAll(UnaryOperator<NodeMap<K, V>> operator) {
        list.replaceAll(operator);
    }

    @Override
    public void sort(Comparator<? super NodeMap<K, V>> c) {
        list.sort(c);
    }

    @Override
    public void clear() {
        list.clear();
    }

    @Override
    public NodeMap<K, V> get(int index) {
        return list.get(index);
    }

    @Override
    public NodeMap<K, V> set(int index, NodeMap<K, V> element) {
        return list.set(index, element);
    }

    @Override
    public void add(int index, NodeMap<K, V> element) {
        list.add(index, element);
    }

    @Override
    public NodeMap<K, V> remove(int index) {
        return list.remove(index);
    }

    @Override
    public int indexOf(Object o) {
        return list.indexOf(o);
    }

    @Override
    public int lastIndexOf(Object o) {
        return list.lastIndexOf(o);
    }

    @Override
    public ListIterator<NodeMap<K, V>> listIterator() {
        return list.listIterator();
    }

    @Override
    public ListIterator<NodeMap<K, V>> listIterator(int index) {
        return list.listIterator(index);
    }

    @Override
    public List<NodeMap<K, V>> subList(int fromIndex, int toIndex) {
        return list.subList(fromIndex, toIndex);
    }

    @Override
    public Spliterator<NodeMap<K, V>> spliterator() {
        return list.spliterator();
    }
}
